ODF provides 2 classes, FW_CScroller and FW_CScrollbarScroller to implement scrolling of your frame's content view. FW_CScrollbarScroller derives from FW_CScroller adding one or two scroll bars. Because the scroller relies on the frame's internal transform (which represents the position of your content inside the frame) it can only be used with the content view and there can be only one instance of this type in each frame.
Notes:
• A future version of ODF will support a more generic "view scroller" independent of the internal transform that lets you scroll any view. To implement scrolling in edit views please see the CScrollEdit class provided as an example in Form.
• If you need more than one scroller in your frame it means that you need more than one content view, in which case you must use embedded frames as UI elements.
Adding a Scroller to Your Frame
The easiest way is to define the scroller in resources along with the frame's views. For a scroll bar scroller you must have defined the scroll bar views earlier in the list of subviews in order to reference their view ids. Here is a typical frame layout resource:
resource FW_RFrameLayout(kMyFrameView)
{
{H,V}, // LayoutSize
{ // Start list of frame's subviews
... // other views
FW_RScrollBar // Horizontal scroll bar
(
kHorzScrollBarID, // view id
{-FW_ONE, V - FW_SBSIZE, H1 - FW_SBSIZE, V1}, // bounds
If you don't use view resources you should create the scroll bar scroller at the end of your frame's CreateSubViews method, after having created the scroll bars and the content view. Then the new scroller is connected using the frame's AdoptScroller method:
void CMyFrame::CreateSubViews(Environment* ev)
{
...
// ----- Create the vertical & horizontal scroll bars inside the frame
• A scroller is deleted automatically by its frame.
• AdoptScroller will throw an exception if you use a scroll bar scroller inside a frame that is its own content view because the scroll bars would end up moving with the rest of the content! A frame that doesn't have a separate content view can only use a basic FW_CScroller instance and can be scrolled with a hand-scrolling or auto-scrolling mechanism.
Handling Scroll Notifications
Once the scroller is created your part has nothing else to do but draw its content correctly in the content view coordinates. Internally the scroll bars send FW_kScrollMsg notifications to the scroller and everything is taken care of by ODF.
Auto Scrolling
Auto scrolling of the frame's content view is demonstrated in the Draw and Container samples. It is implemented by the class FW_CScroller with the following API:
Set the auto-scrolling increment in point, i.e. the x, y values by which the scroller will scroll the content when ScrollBy or AutoScroll is called. The default is zero which means no auto-scrolling. You must call this method to turn auto scrolling on. If you created your views in resources you can also set the AutoScrollIncrement field in the FW_RScroller or FW_RScrollBarScroller resources (see above).
Set the auto-scroll insert, i.e. the distance from the edge of the content view where auto-scroll will occur. The default value is 15 points. If you created your views in resources you can also set the AutoScrollInset field in the FW_RScroller or FW_RScrollBarScroller resources.
FW_CPoint AutoScrollOffset(Environment* ev,
const FW_CPoint& currentPoint,
unsigned long delay = 0);
Returns the auto-scroll offset, i.e. the x,y values measuring the distance of the current point from the edge of the content view (currentPoint is in content coordinates; in absolute values we have (1,1) <= offset <= increment). Normally you pass this offset to ScrollBy to perform the actual scrolling. An offset equal to FW_kZeroPoint means that the current point is outside of the auto-scrolling area defined by the scrolling inset, no scrolling should occur.
The optional delay parameter allows to implement a delay in ticks between each scrolling operation to make the scrolling speed independent of the CPU speed n (1 tick is about 1/60 second) . AutoScrollOffset returns a zero offset until the delay expires.
Scrolls the content view by the given offset. ScrollBy can take an extra argument, gc, a graphic context which will be adjusted to reflect the new frame internal transform. This is useful if you need to perform some drawing during auto scrolling. See a code example below.
Warning: ScrollBy does not make any checking on the offset. Be sure to always call it with a valid offset (like the one returned by AutoScrollOffset).
AutoScroll calls AutoScrollOffset and then ScrollBy giving you a one step API. The current point is in content coordinates. See a code example below.
The optional delay parameter allows to implement a delay in ticks between each scrolling operation to make the scrolling speed independent of the CPU speed (1 tick is about 1/60 second).
void InitializeAutoScroll(Environment* ev);
If you use a scrolling delay you must call InitializeAutoScroll at the beginning of your tracking operation, usually in CMyTracker::BeginTracking().
Two-Step API
The first method is to call AutoScrollOffset() followed by ScrollBy() as in FW_CDropTracker: